package com.xiliubit.cloudpicture.manager;

import cn.hutool.core.io.FileUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.exception.MultiObjectDeleteException;
import com.qcloud.cos.model.DeleteObjectsRequest;
import com.qcloud.cos.model.DeleteObjectsResult;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.ciModel.persistence.PicOperations;
import com.xiliubit.cloudpicture.config.CosClientConfig;
import com.xiliubit.cloudpicture.exception.BusinessException;
import com.xiliubit.cloudpicture.exception.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Slf4j
@Component
public class CosManager {

    @Resource
    CosClientConfig cosClientConfig;

    @Resource
    COSClient cosClient;

    /**
     * 上传文件
     * @param file  要上传的文件
     * @return 文件上传的key
     */
    public String putObject(File file, String filename){
        // 指定文件将要存放的存储桶
        String bucketName = cosClientConfig.getBucket();
        // 指定文件上传到 COS 上的路径，即对象键。例如对象键为 folder/picture.jpg，则表示将文件 picture.jpg 上传到 folder 路径下
        int index = filename.lastIndexOf('.');
        String keySuffix = filename.substring(index);
        String key = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM")) + "." + UUID.randomUUID() + keySuffix;
        // 创建 PutObjectRequest 对象
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file);
        cosClient.putObject(putObjectRequest);
        return key;
    }

    /**
     * 删除文件
     *
     * @param key 要删除的文件的键
     * @return 删除结果
     */
    @Async("asyncDeletePictureExecutor")
    public void deleteObject(String key){
        // 检查参数是否为空
        if (key == null) {
            log.warn("尝试删除空键的文件");
            return;
        }

        // Bucket 的命名格式为 BucketName-APPID ，此处填写的存储桶名称必须为此格式
        String bucketName = cosClientConfig.getBucket();
        // 指定被删除的文件在 COS 上的路径，即对象键。例如对象键为 folder/picture.jpg，则表示删除位于 folder 路径下的文件 picture.jpg
        String host = cosClientConfig.getHost();
        String filePath = key.substring(host.length());
        try {
            log.info("开始删除图片文件: {}", filePath);
            cosClient.deleteObject(bucketName, filePath);
        } catch (CosClientException e) {
            log.info("cos file delete error, filepath = {}", filePath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除文件失败");
        }
    }

    /**
     * 批量删除文件
     *
     * @param keyList 要删除的文件的键列表
     * @return 删除结果
     */
    @Async("asyncDeletePictureExecutor")
    public void deleteObjectList(List<DeleteObjectsRequest.KeyVersion> keyList){
        // Bucket 的命名格式为 BucketName-APPID ，此处填写的存储桶名称必须为此格式
        String bucketName = cosClientConfig.getBucket();
        DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName);
        log.info("开始批量删除图片文件");
        deleteObjectsRequest.setKeys(keyList);
        try {
            DeleteObjectsResult deleteObjectsResult = cosClient.deleteObjects(deleteObjectsRequest);
            List<DeleteObjectsResult.DeletedObject> deleteObjectResultArray = deleteObjectsResult.getDeletedObjects();
        } catch (MultiObjectDeleteException mde) {
            // 如果部分删除成功部分失败, 返回 MultiObjectDeleteException
            List<DeleteObjectsResult.DeletedObject> deleteObjects = mde.getDeletedObjects();
            List<MultiObjectDeleteException.DeleteError> deleteErrors = mde.getErrors();
        } catch (CosServiceException e) {
            log.info("cos file delete error, ", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除文件失败");
        } catch (CosClientException e) {
            log.info("cos file delete error, ", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除文件失败");
        }
        log.info("图片文件删除完成");
    }

    /**
     * 上传图片（附带图片信息）
     *
     * @param file 要上传的文件
     * @param key  文件的url
     */
    public PutObjectResult putPictureObject(File file, String key) {
        PutObjectRequest putObjectRequest = new PutObjectRequest(cosClientConfig.getBucket(), key, file);
        // 对图像进行处理
        PicOperations picOperations = new PicOperations();
        // 设置是否返回图片信息
        picOperations.setIsPicInfo(1);
        // 添加图片处理规则
        List<PicOperations.Rule> ruleList = new LinkedList<>();
        // 对图片进行压缩，转为.webp格式
        String webpKey = FileUtil.mainName(key) + ".webp";
        PicOperations.Rule webpRule = new PicOperations.Rule();
        webpRule.setBucket(cosClientConfig.getBucket());
        webpRule.setRule("imageMogr2/format/webp");
        webpRule.setFileId(webpKey);
        ruleList.add(webpRule);

        // 只对大于2KB的图片进行缩略图处理
        if (file.length() > 2 * 1024){
            // 对图片新增缩略图
            String thumbnailKey = FileUtil.mainName(key) + "_thumbnail." + FileUtil.getSuffix(key);
            PicOperations.Rule thumbnailRule = new PicOperations.Rule();
            thumbnailRule.setBucket(cosClientConfig.getBucket());
            thumbnailRule.setRule("imageMogr2/thumbnail/255x255>");
            thumbnailRule.setFileId(thumbnailKey);
            ruleList.add(thumbnailRule);
        }
        // 设置图片处理参数
        picOperations.setRules(ruleList);
        putObjectRequest.setPicOperations(picOperations);
        // 上传图片
        return cosClient.putObject(putObjectRequest);
    }
}
